package fashion

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"jihe.common/protos/base_server/proto"
	"jihe.common/tool"
)

func (s *Model) Create(in *proto.BaseFashion) (ret *proto.BaseFashion, err error) {
	ret = new(proto.BaseFashion)
	in.Id = fmt.Sprintf("%d", tool.GetSnowflakeId())
	in.CreatedAt = time.Now().Format("2006-01-02 15:04:05")
	in.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("INSERT INTO %s (id, name, person_type, solar_term, tp, style, price, cover, detail_url, created_at, updated_at)VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)", s.Name)
	_, err = s.Db.Exec(sqlStr, in.Id, in.Name, in.PersonType, in.SolarTerm, in.Tp, in.Style, in.Price, in.Cover, in.DetailUrl, in.CreatedAt, in.UpdatedAt)
	if err != nil {
		return
	}
	ret = in
	return
}

func (s *Tx) Create(in *proto.BaseFashion) (err error) {
	sqlStr := fmt.Sprintf("INSERT INTO %s (id, name, cover, detail_url, obj_url, dxf_url, cutpart_border_point, super_fashion_id, algorithm_param)VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9)", s.Name)
	algorithmParamJson, _ := json.Marshal(in.AlgorithmParam)
	_, err = s.Db.Exec(sqlStr, in.Id, in.Name, in.Cover, in.DetailUrl, in.ObjUrl, in.DxfUrl, in.CutpartBorderPoint, in.SuperFashionId, string(algorithmParamJson))
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateCutpartBorderPointById(id string, url string, objUrl string) (err error) {
	sqlStr := fmt.Sprintf("update %s set cutpart_border_point = $1, obj_url = $2 where id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, url, objUrl, id)
	if err != nil {
		return
	}
	return
}

func (s *Tx) Delete(id string) (err error) {
	sqlStr := fmt.Sprintf("delete from %s where id = $1", s.Name)
	_, err = s.Db.Exec(sqlStr, id)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetList(in *proto.BaseGetFashionListReq) (ret *proto.BaseGetFashionListRes, err error) {
	ret = new(proto.BaseGetFashionListRes)
	sqlStr := fmt.Sprintf("SELECT id, name, person_type, solar_term, tp, style, price, cover, detail_url, obj_url, dxf_url, created_at, updated_at, status, recommended, super_fashion_id FROM %s WHERE 1 = 1", s.Name)
	sqlCountStr := fmt.Sprintf("SELECT COUNT(0) FROM %s WHERE 1 = 1", s.Name)
	conditionSql := ""
	args := make([]interface{}, 0)
	if in.Search != nil {
		if in.Search.Name != "" {
			in.Search.Name = "%" + in.Search.Name + "%"
			args = append(args, in.Search.Name)
			conditionSql += fmt.Sprintf(" AND name ILIKE $%d", len(args))
		}
		if in.Search.Id != "" {
			args = append(args, in.Search.Id)
			conditionSql += fmt.Sprintf(" AND id = $%d", len(args))
		}
		if in.Search.PersonType != 0 {
			args = append(args, in.Search.PersonType)
			conditionSql += fmt.Sprintf(" AND person_type = $%d", len(args))
		}
		if in.Search.Tp != 0 {
			args = append(args, in.Search.Tp)
			conditionSql += fmt.Sprintf(" AND tp = $%d", len(args))
		}
		if in.Search.Style != 0 {
			args = append(args, in.Search.Style)
			conditionSql += fmt.Sprintf(" AND style = $%d", len(args))
		}
		if in.Search.Status != -1 {
			args = append(args, in.Search.Status)
			conditionSql += fmt.Sprintf(" AND status = $%d", len(args))
		}
	}
	_ = s.Db.QueryRow(sqlCountStr+conditionSql, args...).Scan(&ret.Total)
	args = append(args, in.PageSize)
	sqlStr = fmt.Sprintf("%s ORDER BY created_at DESC LIMIT $%d", sqlStr+conditionSql, len(args))
	args = append(args, in.Page*in.PageSize)
	sqlStr += fmt.Sprintf(" OFFSET $%d", len(args))
	rows, e := s.Db.Query(sqlStr, args...)
	if e != nil {
		err = e
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.BaseFashion{}
		var (
			createdAt *time.Time
			updatedAt *time.Time
		)
		err = rows.Scan(&item.Id, &item.Name, &item.PersonType, &item.SolarTerm, &item.Tp, &item.Style, &item.Price, &item.Cover, &item.DetailUrl, &item.ObjUrl, &item.DxfUrl, &createdAt, &updatedAt, &item.Status, &item.Recommended, &item.SuperFashionId)
		if err != nil {
			return
		}
		if createdAt != nil {
			item.CreatedAt = createdAt.Format("2006-01-02 15:04:05")
		}
		if updatedAt != nil {
			item.UpdatedAt = updatedAt.Format("2006-01-02 15:04:05")
		}
		ret.List = append(ret.List, item)
	}
	return
}

func (s *Model) GetDetail(id string) (ret *proto.BaseFashion, err error) {
	ret = new(proto.BaseFashion)
	sqlStr := fmt.Sprintf("SELECT id, name, person_type, solar_term, tp, style, price, cover, detail_url, obj_url, dxf_url, created_at, updated_at, status, algorithm_param, cutpart_border_point, super_fashion_id FROM %s WHERE id = $1", s.Name)
	var (
		createdAt *time.Time
		updatedAt *time.Time
	)
	var algorithmParam []byte
	err = s.Db.QueryRow(sqlStr, id).Scan(&ret.Id, &ret.Name, &ret.PersonType, &ret.SolarTerm, &ret.Tp, &ret.Style, &ret.Price, &ret.Cover, &ret.DetailUrl, &ret.ObjUrl, &ret.DxfUrl, &createdAt, &updatedAt, &ret.Status, &algorithmParam, &ret.CutpartBorderPoint, &ret.SuperFashionId)
	if err != nil {
		return
	}
	json.Unmarshal(algorithmParam, &ret.AlgorithmParam)
	if createdAt != nil {
		ret.CreatedAt = createdAt.Format("2006-01-02 15:04:05")
	}
	if updatedAt != nil {
		ret.UpdatedAt = updatedAt.Format("2006-01-02 15:04:05")
	}
	return
}

func (s *Model) Update(req *proto.BaseFashion) (ret *proto.BaseFashion, err error) {
	ret = new(proto.BaseFashion)
	sqlStr := fmt.Sprintf("UPDATE %s SET name = $1, person_type = $2, solar_term = $3, tp = $4, style = $5, price = $6, cover = $7, detail_url = $8, updated_at = $9 WHERE id = $10", s.Name)
	_, err = s.Db.Exec(sqlStr, req.Name, req.PersonType, req.SolarTerm, req.Tp, req.Style, req.Price, req.Cover, req.DetailUrl, time.Now().Format("2006-01-02 15:04:05"), req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Tx) UpdateObjUrl(fashionId, objUrl string) (err error) {
	sqlStr := fmt.Sprintf("UPDATE %s SET obj_url = $1, updated_at = $2 WHERE id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, objUrl, time.Now().Format("2006-01-02 15:04:05"), fashionId)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateDxfUrl(fashionId, dxfUrl string) (err error) {
	sqlStr := fmt.Sprintf("UPDATE %s SET dxf_url = $1, updated_at = $2 WHERE id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, dxfUrl, time.Now().Format("2006-01-02 15:04:05"), fashionId)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateAlgorithmParam(req *proto.BaseFashion) (err error) {
	jsonb, err := json.Marshal(req.AlgorithmParam)
	if err != nil {
		return
	}
	sqlStr := fmt.Sprintf("update %s set algorithm_param = algorithm_param::jsonb || $1::jsonb where id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, string(jsonb), req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Tx) UpdateAlgorithmParam(req *proto.BaseFashion) (err error) {
	jsonb, err := json.Marshal(req.AlgorithmParam)
	if err != nil {
		return
	}
	sqlStr := fmt.Sprintf("update %s set algorithm_param = algorithm_param::jsonb || $1::jsonb where id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, string(jsonb), req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateAlgorithmParamById(id string, algorithmParam *proto.BaseFashionAlgorithmParam) (err error) {
	jsonb, err := json.Marshal(algorithmParam)
	if err != nil {
		return
	}
	sqlStr := fmt.Sprintf("update %s set algorithm_param = algorithm_param::jsonb || $1::jsonb where id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, string(jsonb), id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateBorderPointUrlById(id, url string) (err error) {
	sqlStr := fmt.Sprintf("update %s set cutpart_border_point = $1 where id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, url, id)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetTpByDistinct() (ret []int64, err error) {
	sqlStr := fmt.Sprintf("select distinct(tp) from %s where status = 2", s.Name)
	rows, err := s.Db.Query(sqlStr)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var tp int64
		err = rows.Scan(&tp)
		if err != nil {
			return
		}
		ret = append(ret, tp)
	}
	return
}

func (s *Model) GetTpByRecommended() (ret *proto.BaseGetFashionListRes, err error) {
	ret = new(proto.BaseGetFashionListRes)
	sqlStr := fmt.Sprintf("select id, name, person_type, solar_term, tp, style, price, cover, detail_url, obj_url, created_at from %s where recommended = 2 and status = 2", s.Name)
	rows, err := s.Db.Query(sqlStr)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.BaseFashion{}
		var createdTime *time.Time
		err = rows.Scan(&item.Id, &item.Name, &item.PersonType, &item.SolarTerm, &item.Tp, &item.Style, &item.Price, &item.Cover, &item.DetailUrl, &item.ObjUrl, &createdTime)
		if err != nil {
			return
		}
		if createdTime != nil {
			item.CreatedAt = createdTime.Format("2006-01-02 15:04:05")
		}
		ret.List = append(ret.List, item)
	}
	return
}

func (s *Model) GetListByIds(in *proto.BaseGetFashionListByIdsReq) (ret []*proto.BaseFashion, err error) {
	args := make([]string, len(in.Ids))
	vals := make([]interface{}, len(in.Ids))
	for k, v := range in.Ids {
		args[k] = fmt.Sprintf("$%d", k+1)
		vals[k] = v
	}
	sqlStr := fmt.Sprintf("SELECT id, name, person_type, solar_term, tp, style, price, cover, detail_url, obj_url, dxf_url, created_at, updated_at, status FROM %s WHERE id in ("+strings.Join(args, ",")+")", s.Name)
	rows, e := s.Db.Query(sqlStr, vals...)
	if e != nil {
		err = e
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.BaseFashion{}
		var (
			createdAt *time.Time
			updatedAt *time.Time
		)
		err = rows.Scan(&item.Id, &item.Name, &item.PersonType, &item.SolarTerm, &item.Tp, &item.Style, &item.Price, &item.Cover, &item.DetailUrl, &item.ObjUrl, &item.DxfUrl, &createdAt, &updatedAt, &item.Status)
		if err != nil {
			return
		}
		if createdAt != nil {
			item.CreatedAt = createdAt.Format("2006-01-02 15:04:05")
		}
		if updatedAt != nil {
			item.UpdatedAt = updatedAt.Format("2006-01-02 15:04:05")
		}
		ret = append(ret, item)
	}
	return
}

func (s *Model) UpdateRecommended(id string, recommended int64) (err error) {
	sqlStr := fmt.Sprintf("update %s set recommended = $1, updated_at = $2 where id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, recommended, time.Now().Format("2006-01-02 15:04:05"), id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateStatus(id string, status int64) (err error) {
	sqlStr := fmt.Sprintf("update %s set status = $1, updated_at = $2 where id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, status, time.Now().Format("2006-01-02 15:04:05"), id)
	if err != nil {
		return
	}
	return
}
